/*!
 * \file ExecMocker.cpp
 * \project WonderTrader
 *
 * \author Wesley
 * \date 2020/03/30
 * 
 * \brief 执行器模拟器实现文件
 * 
 * \details 本文件实现了ExecMocker类的各种方法，用于在WonderTrader回测框架中模拟交易执行器的行为。
 *          主要实现功能包括：
 *          - 动态加载执行器工厂模块
 *          - 模拟订单执行和撮合
 *          - 处理市场数据回调
 *          - 管理持仓和目标仓位
 *          - 记录交易日志和统计信息
 *          - 与回测数据回放器集成
 */
#include "ExecMocker.h"
#include "WtHelper.h"

#include "../Includes/WTSVariant.hpp"
#include "../Share/TimeUtils.hpp"
#include "../Share/decimal.h"
#include "../WTSTools/WTSLogger.h"

#include <boost/filesystem.hpp>

#define PRICE_DOUBLE_TO_INT_P(x) ((int32_t)((x)*10000.0 + 0.5))
#define PRICE_DOUBLE_TO_INT_N(x) ((int32_t)((x)*10000.0 - 0.5))
#define PRICE_DOUBLE_TO_INT(x) (((x)==DBL_MAX)?0:((x)>0?PRICE_DOUBLE_TO_INT_P(x):PRICE_DOUBLE_TO_INT_N(x)))

extern uint32_t makeLocalOrderID();

/*!
 * \brief ExecMocker构造函数
 * 
 * \param replayer 历史数据回放器指针
 * 
 * \details 初始化执行器模拟器对象，设置历史数据回放器引用并初始化各种统计变量。
 *          构造函数将所有计数器和状态变量初始化为默认值，为后续的交易模拟做准备。
 *          
 *          初始化的成员变量：
 *          - _replayer: 历史数据回放器引用
 *          - _position: 当前持仓为0
 *          - _undone: 未完成订单数量为0
 *          - 各种统计计数器初始化为0
 *          - _sig_px: 信号价格初始化为DBL_MAX
 *          - _last_tick: 最后一个tick数据指针初始化为NULL
 */
ExecMocker::ExecMocker(HisDataReplayer* replayer)
	: _replayer(replayer)
	, _position(0)
	, _undone(0)
	, _ord_qty(0)
	, _ord_cnt(0)
	, _cacl_cnt(0)
	, _cacl_qty(0)
	, _sig_cnt(0)
	, _sig_px(DBL_MAX)
	, _last_tick(NULL)
{
}

/*!
 * \brief ExecMocker析构函数
 * 
 * \details 清理执行器模拟器资源，主要是释放最后一个tick数据的内存。
 *          如果_last_tick指针非空，则调用其release()方法释放内存，
 *          避免内存泄漏。
 */
ExecMocker::~ExecMocker()
{
	if (_last_tick)
		_last_tick->release();
}

/*!
 * \brief 初始化执行器模拟器
 * 
 * \param cfg 配置参数
 * \return 初始化是否成功
 * 
 * \details 根据配置参数初始化执行器模拟器。主要完成以下工作：
 *          1. 从配置中读取模块路径、合约代码、周期等参数
 *          2. 设置交易模式和单位手数
 *          3. 初始化撮合引擎
 *          4. 动态加载执行器工厂模块
 *          5. 创建执行器单元实例
 *          
 *          交易模式说明：
 *          - 0: 乒乓模式（多空来回切换）
 *          - -1: 一直做空（持续减仓）
 *          - +1: 一直做多（持续加仓）
 *          
 *          错误处理：
 *          - 模块加载失败时返回false
 *          - 执行器工厂创建失败时释放模块并返回false
 */
bool ExecMocker::init(WTSVariant* cfg)
{
	// 从配置中读取基本参数
	const char* module = cfg->getCString("module");
	_code = cfg->getCString("code");
	_period = cfg->getCString("period");
	_volunit = cfg->getDouble("volunit");
	_volmode = cfg->getInt32("volmode");	// 交易模式：0-乒乓模式；-1-一直做空；+1-一直做多

	// 初始化撮合引擎
	_matcher.regisSink(this);
	_matcher.init(cfg->get("matcher"));

	// 动态加载执行器工厂模块
	DllHandle hInst = DLLHelper::load_library(module);
	if (hInst == NULL)
		return false;

	// 获取执行器工厂创建函数
	FuncCreateExeFact creator = (FuncCreateExeFact)DLLHelper::get_symbol(hInst, "createExecFact");
	if (creator == NULL)
	{
		DLLHelper::free_library(hInst);
		return false;
	}

	// 初始化执行器工厂
	_factory._module_inst = hInst;
	_factory._module_path = module;
	_factory._creator = creator;
	_factory._remover = (FuncDeleteExeFact)DLLHelper::get_symbol(hInst, "deleteExecFact");
	_factory._fact = _factory._creator();

	// 创建执行器单元
	WTSVariant* cfgExec = cfg->get("executer");
	if (cfgExec)
	{
		_exec_unit = _factory._fact->createExeUnit(cfgExec->getCString("name"));
		_exec_unit->init(this, _code.c_str(), cfgExec->get("params"));
		_id = cfgExec->getCString("id");
	}

	return true;
}

/*!
 * \brief 获取品种信息
 * 
 * \param stdCode 标准合约代码
 * \return 品种信息指针
 * 
 * \details 通过历史数据回放器获取指定合约的品种信息。该函数是ICtaStraCtx接口的实现，
 *          为执行器提供品种相关的基础信息，如交易单位、最小变动价位、涨跌停幅度等。
 */
WTSCommodityInfo* ExecMocker::getCommodityInfo(const char* stdCode)
{
	return _replayer->get_commodity_info(stdCode);
}

/*!
 * \brief 获取交易时段信息
 * 
 * \param stdCode 标准合约代码
 * \return 交易时段信息指针
 * 
 * \details 通过历史数据回放器获取指定合约的交易时段信息。该函数返回合约的
 *          交易时间安排，包括开盘时间、收盘时间、休息时间等。
 */
WTSSessionInfo* ExecMocker::getSessionInfo(const char* stdCode)
{
	return _replayer->get_session_info(stdCode, true);
}

/*!
 * \brief 获取当前时间
 * 
 * \return 当前时间戳（微秒级）
 * 
 * \details 获取回测环境中的当前时间。该函数将回放器的日期和时间信息
 *          组合成一个完整的时间戳，精度到微秒级。这个时间是回测数据
 *          的时间，而不是系统当前时间。
 */
uint64_t ExecMocker::getCurTime()
{
	return TimeUtils::makeTime(_replayer->get_date(), _replayer->get_raw_time() * 100000 + _replayer->get_secs());
}

/*!
 * \brief 处理K线收盘事件
 * 
 * \param stdCode 标准合约代码
 * \param period K线周期
 * \param times 周期倍数
 * \param newBar 新的K线数据
 * 
 * \details 处理K线收盘事件的回调函数。当前实现为空，可以根据需要添加
 *          K线收盘时的处理逻辑，如统计计算、策略触发等。
 */
void ExecMocker::handle_bar_close(const char* stdCode, const char* period, uint32_t times, WTSBarStruct* newBar)
{
	//throw std::logic_error("The method or operation is not implemented.");
}

/*!
 * \brief 处理交易时段开始事件
 * 
 * \param curTDate 当前交易日期
 * 
 * \details 处理交易时段开始事件的回调函数。当前实现为空，可以根据需要添加
 *          交易时段开始时的处理逻辑，如初始化当日状态、清理数据等。
 */
void ExecMocker::handle_session_begin(uint32_t curTDate)
{
	//throw std::logic_error("The method or operation is not implemented.");
}

/*!
 * \brief 处理交易时段结束事件
 * 
 * \param curTDate 当前交易日期
 * 
 * \details 处理交易时段结束事件的回调函数。主要完成以下工作：
 *          1. 清理撮合引擎的未完成订单
 *          2. 重置未完成订单计数
 *          3. 输出当日交易统计信息
 *          
 *          统计信息包括：
 *          - 总委托次数和数量
 *          - 总撤单次数和数量  
 *          - 总信号次数
 */
void ExecMocker::handle_session_end(uint32_t curTDate)
{
	// 清理撮合引擎的未完成订单
	_matcher.clear();
	_undone = 0;

	// 输出当日交易统计信息
	WTSLogger::info_f("Total entrust:{}, total quantity:{}, total cancels:{}, total cancel quantity:{}, total signals:{}", 
		_ord_cnt, _ord_qty, _cacl_cnt, _cacl_qty, _sig_cnt);
}

/*!
 * \brief 处理Tick数据事件
 * 
 * \param stdCode 标准合约代码
 * \param curTick 当前Tick数据
 * 
 * \details 处理新的Tick数据到达事件。主要完成以下工作：
 *          1. 更新最新的Tick数据缓存
 *          2. 将Tick数据传递给撮合引擎处理
 *          3. 通知执行器单元处理新的市场数据
 *          
 *          内存管理：
 *          - 释放之前缓存的Tick数据
 *          - 保持对新Tick数据的引用
 *          - 确保内存正确释放和引用计数
 */
void ExecMocker::handle_tick(const char* stdCode, WTSTickData* curTick)
{
 	// 释放之前的Tick数据
 	if (_last_tick)
	{
		_last_tick->release();
		_last_tick = NULL;
	}

	// 缓存新的Tick数据
	_last_tick = curTick;
	_last_tick->retain();
	
	// 将Tick数据传递给撮合引擎
	_matcher.handle_tick(stdCode, curTick);

	// 通知执行器单元处理新的市场数据
	if (_exec_unit)
		_exec_unit->on_tick(curTick);
}

/*!
 * \brief 初始化处理
 * 
 * \details 执行器模拟器的初始化处理函数。主要完成以下工作：
 *          1. 解析K线周期参数（基础周期和倍数）
 *          2. 获取历史K线数据切片进行预加载
 *          3. 订阅目标合约的Tick数据
 *          4. 初始化交易日志文件头
 *          5. 通知执行器单元通道就绪
 *          6. 设置初始信号时间和目标仓位
 *          
 *          K线周期解析：
 *          - 单字符周期：如"m"（分钟）、"d"（日线）等
 *          - 复合周期：如"m5"（5分钟）、"d1"（日线）等
 *          
 *          交易日志格式：
 *          localid,signaltime,ordertime,bs,sigprice,ordprice,lmtprice,tradetime,trdprice,qty,sigtimespan,exectime,cancel
 */
void ExecMocker::handle_init()
{
	// 解析K线周期参数
	std::string basePeriod = "";
	uint32_t times = 1;
	if (_period.size() > 1)
	{
		basePeriod.append(_period.c_str(), 1);
		times = strtoul(_period.c_str() + 1, NULL, 10);
	}
	else
	{
		basePeriod = _period;
	}

	// 获取历史K线数据进行预加载
	WTSKlineSlice* kline = _replayer->get_kline_slice(_code.c_str(), basePeriod.c_str(),  10, times, true);
	if (kline)
		kline->release();

	// 订阅目标合约的Tick数据
	_replayer->sub_tick(0, _code.c_str());

	// 初始化交易日志文件头
	_trade_logs << "localid,signaltime,ordertime,bs,sigprice,ordprice,lmtprice,tradetime,trdprice,qty,sigtimespan,exectime,cancel" << std::endl;

	// 通知执行器单元通道就绪
	_exec_unit->on_channel_ready();

	// 设置初始信号时间
	_sig_time = (uint64_t)_replayer->get_date() * 10000 + _replayer->get_raw_time();

	// 设置初始目标仓位
	_exec_unit->set_position(_code.c_str(), _volunit);
	WTSLogger::info_f("Target position updated at the beginning: {}", _volunit);
}

/*!
 * \brief 处理调度事件
 * 
 * \param uDate 日期
 * \param uTime 时间
 * 
 * \details 处理定时调度事件，根据交易模式更新目标仓位。主要功能：
 *          1. 跳过收盘时间（1500）的调度
 *          2. 获取当前信号价格（最新价或昨收价）
 *          3. 根据交易模式计算新的目标仓位
 *          4. 通知执行器单元更新目标仓位
 *          5. 记录信号计数
 *          
 *          交易模式说明：
 *          - 0: 乒乓模式，多空来回切换
 *          - -1: 持续减仓模式
 *          - +1: 持续加仓模式
 */
void ExecMocker::handle_schedule(uint32_t uDate, uint32_t uTime)
{
	// 跳过收盘时间的调度
	if (uTime == 1500)
		return;

	// 获取信号价格
	_sig_px = _last_tick->price();
	if (_sig_px == DBL_MAX || _sig_px == FLT_MAX)
		_sig_px = _last_tick->preclose();

	// 记录信号时间
	_sig_time = (uint64_t)uDate * 10000 + uTime;
	
	// 根据交易模式计算目标仓位
	if(_volmode == 0)
	{
		// 乒乓模式：多空来回切换
		if (_position <= 0)
			_target = _volunit;
		else
			_target = -_volunit;
	}
	else if (_volmode == -1)
	{
		// 持续减仓模式
		_target -= _volunit;
	}
	else if (_volmode == 1)
	{
		// 持续加仓模式
		_target += _volunit;
	}

	// 通知执行器单元更新目标仓位
	_exec_unit->set_position(_code.c_str(), _target);
	WTSLogger::info_f("Target position updated @{}.{}: {}", uDate, uTime, _volunit);
	_sig_cnt++;
}

/*!
 * \brief 获取Tick数据切片
 * 
 * \param stdCode 标准合约代码
 * \param count 数据条数
 * \param etime 结束时间（可选）
 * \return Tick数据切片指针
 * 
 * \details 通过历史数据回放器获取指定合约的Tick数据切片。
 *          该函数是ICtaStraCtx接口的实现，为执行器提供历史Tick数据访问能力。
 */
WTSTickSlice* ExecMocker::getTicks(const char* stdCode, uint32_t count, uint64_t etime /*= 0*/)
{
	return _replayer->get_tick_slice(stdCode, count, etime);
}

/*!
 * \brief 获取最新Tick数据
 * 
 * \param stdCode 标准合约代码
 * \return 最新Tick数据指针
 * 
 * \details 通过历史数据回放器获取指定合约的最新Tick数据。
 *          该函数是ICtaStraCtx接口的实现，为执行器提供最新市场数据访问能力。
 */
WTSTickData* ExecMocker::grabLastTick(const char* stdCode)
{
	return _replayer->get_last_tick(stdCode);
}

/*!
 * \brief 获取持仓数量
 * 
 * \param stdCode 标准合约代码
 * \param validOnly 是否只返回有效持仓（未使用）
 * \param flag 持仓标志（未使用）
 * \return 当前持仓数量
 * 
 * \details 返回指定合约的当前持仓数量。该函数是ICtaStraCtx接口的实现，
 *          为执行器提供持仓查询能力。正数表示多头持仓，负数表示空头持仓。
 */
double ExecMocker::getPosition(const char* stdCode, bool validOnly /* = true */, int32_t flag /* = 3 */)
{
	return _position;
}

/*!
 * \brief 获取订单信息
 * 
 * \param stdCode 标准合约代码
 * \return 订单映射表指针（当前实现返回NULL）
 * 
 * \details 获取指定合约的订单信息映射表。当前实现返回NULL，
 *          表示不提供详细的订单信息查询功能。如需要可以扩展实现。
 */
OrderMap* ExecMocker::getOrders(const char* stdCode)
{
	return NULL;
}

/*!
 * \brief 获取未完成订单数量
 * 
 * \param stdCode 标准合约代码
 * \return 未完成订单数量
 * 
 * \details 返回指定合约的未完成订单数量。该函数是ICtaStraCtx接口的实现，
 *          为执行器提供挂单数量查询能力。正数表示买单，负数表示卖单。
 */
double ExecMocker::getUndoneQty(const char* stdCode)
{
	return _undone;
}

/*!
 * \brief 提交买单
 * 
 * \param stdCode 标准合约代码
 * \param price 委托价格
 * \param qty 委托数量
 * \param bForceClose 是否强制平仓（未使用）
 * \return 订单ID列表
 * 
 * \details 向撮合引擎提交买单委托。主要完成以下工作：
 *          1. 构造当前时间戳
 *          2. 调用撮合引擎的买单接口
 *          3. 更新委托统计信息（次数和数量）
 *          4. 更新未完成订单计数
 *          5. 记录日志信息
 */
OrderIDs ExecMocker::buy(const char* stdCode, double price, double qty, bool bForceClose /* = false */)
{
	// 构造当前时间戳
	uint64_t curTime = (uint64_t)_replayer->get_date() * 1000000000 + (uint64_t)_replayer->get_raw_time() * 100000 + _replayer->get_secs();
	
	// 提交买单到撮合引擎
	OrderIDs ret = _matcher.buy(stdCode, price, qty, curTime);

	if(!ret.empty())
	{
		// 更新委托统计
		_ord_cnt++;
		_ord_qty += qty;

		// 更新未完成订单计数
		_undone += (int32_t)qty;
		WTSLogger::info_f("{}, undone orders updated: {}", __FUNCTION__, _undone);
	}

	return ret;
}

/*!
 * \brief 提交卖单
 * 
 * \param stdCode 标准合约代码
 * \param price 委托价格
 * \param qty 委托数量
 * \param bForceClose 是否强制平仓（未使用）
 * \return 订单ID列表
 * 
 * \details 向撮合引擎提交卖单委托。主要完成以下工作：
 *          1. 构造当前时间戳
 *          2. 调用撮合引擎的卖单接口
 *          3. 更新委托统计信息（次数和数量）
 *          4. 更新未完成订单计数
 *          5. 记录日志信息
 */
OrderIDs ExecMocker::sell(const char* stdCode, double price, double qty, bool bForceClose /* = false */)
{
	// 构造当前时间戳
	uint64_t curTime = (uint64_t)_replayer->get_date() * 1000000000 + (uint64_t)_replayer->get_raw_time() * 100000 + _replayer->get_secs();
	
	// 提交卖单到撮合引擎
	OrderIDs ret = _matcher.sell(stdCode, price, qty, curTime);

	if(!ret.empty())
	{
		// 更新委托统计
		_ord_cnt++;
		_ord_qty += qty;
	
		// 更新未完成订单计数（卖单为负）
		_undone -= (int32_t)qty;
		WTSLogger::info_f("{}, undone orders updated: {}", __FUNCTION__, _undone);
	}

	return ret;
}

/*!
 * \brief 撤销指定订单
 * 
 * \param localid 本地订单ID
 * \return 撤单是否成功
 * 
 * \details 撤销指定ID的订单。主要完成以下工作：
 *          1. 调用撮合引擎撤销订单
 *          2. 检查撤单结果（变化量为0表示失败）
 *          3. 更新未完成订单计数
 *          4. 更新撤单统计信息
 *          5. 记录日志信息
 */
bool ExecMocker::cancel(uint32_t localid)
{
	// 调用撮合引擎撤销订单
	double change = _matcher.cancel(localid);
	if (decimal::eq(change, 0))
		return false;

	// 更新统计信息
	_undone -= change;
	_cacl_cnt++;
	_cacl_qty += abs(change);
	WTSLogger::info_f("{}, undone orders updated: {}", __FUNCTION__, _undone);

	return true;
}

/*!
 * \brief 批量撤单
 * 
 * \param stdCode 标准合约代码
 * \param isBuy 是否为买单
 * \param qty 撤单数量（0表示撤销所有）
 * \return 被撤销的订单ID列表
 * 
 * \details 根据合约代码和买卖方向批量撤销订单。主要完成以下工作：
 *          1. 调用撮合引擎批量撤单接口
 *          2. 在回调函数中更新未完成订单计数和撤单统计
 *          3. 记录日志信息
 */
OrderIDs ExecMocker::cancel(const char* stdCode, bool isBuy, double qty /*= 0*/)
{
	// 调用撮合引擎批量撤单，使用lambda回调更新统计
	OrderIDs ret = _matcher.cancel(stdCode, isBuy, qty, [this](double change) {
		_undone -= change;

		_cacl_cnt++;
		_cacl_qty += abs(change);
	});
	WTSLogger::info_f("{}, undone orders updated: {}", __FUNCTION__, _undone);

	return ret;
}

/*!
 * \brief 写入日志
 * 
 * \param message 日志消息
 * 
 * \details 向执行器专用日志通道写入日志信息。该函数是ICtaStraCtx接口的实现，
 *          为执行器提供日志记录能力。日志会写入到以执行器ID命名的专用日志文件中。
 */
void ExecMocker::writeLog(const char* message)
{
	WTSLogger::log_dyn_raw("executer", _id.c_str(), LL_INFO, message);
}

/*!
 * \brief 处理委托确认事件
 * 
 * \param localid 本地订单ID
 * \param stdCode 标准合约代码
 * \param bSuccess 委托是否成功
 * \param message 委托消息
 * \param ordTime 委托时间
 * 
 * \details 处理来自撮合引擎的委托确认事件。将委托结果转发给执行器单元，
 *          让执行器知道订单是否已成功提交到交易所。
 */
void ExecMocker::handle_entrust(uint32_t localid, const char* stdCode, bool bSuccess, const char* message, uint64_t ordTime)
{
	_exec_unit->on_entrust(localid, stdCode, bSuccess, message);
}

/*!
 * \brief 处理订单状态更新事件
 * 
 * \param localid 本地订单ID
 * \param stdCode 标准合约代码
 * \param isBuy 是否为买单
 * \param leftover 剩余数量
 * \param price 订单价格
 * \param isCanceled 是否已撤销
 * \param ordTime 订单时间
 * 
 * \details 处理来自撮合引擎的订单状态更新事件。主要功能：
 *          1. 计算时间戳和Unix时间
 *          2. 如果是撤单，记录到交易日志并更新未完成订单计数
 *          3. 将订单状态更新转发给执行器单元
 *          
 *          交易日志记录格式：
 *          localid,signaltime,ordertime,bs,sigprice,ordprice,lmtprice,tradetime,trdprice,qty,sigtimespan,exectime,cancel
 */
void ExecMocker::handle_order(uint32_t localid, const char* stdCode, bool isBuy, double leftover, double price, bool isCanceled, uint64_t ordTime)
{
	// 计算时间戳
	uint64_t curTime = (uint64_t)_last_tick->actiondate() * 1000000000 + _last_tick->actiontime();
	uint64_t curUnixTime = TimeUtils::makeTime(_last_tick->actiondate(), _last_tick->actiontime());

	uint64_t sigUnixTime = TimeUtils::makeTime((uint32_t)(_sig_time / 10000), _sig_time % 10000 * 100000);
	uint64_t ordUnixTime = TimeUtils::makeTime((uint32_t)(ordTime / 1000000000), ordTime % 1000000000);

	// 如果是撤单，记录交易日志
	if(isCanceled)
	{
		if (_sig_px == DBL_MAX)
			_sig_px = _last_tick->preclose();

		_trade_logs << localid << ","
			<< _sig_time << ","
			<< ordTime << ","
			<< (isBuy ? "B" : "S") << ","
			<< _sig_px << ","
			<< 0 << ","
			<< price << ","
			<< curTime << ","
			<< price << ","
			<< 0 << ","
			<< curUnixTime - sigUnixTime << ","
			<< curUnixTime - ordUnixTime << ","
			<< "true" << std::endl;

		// 更新未完成订单计数
		_undone -= leftover * (isBuy ? 1 : -1);
		WTSLogger::info_f("{}, undone orders updated: {}", __FUNCTION__, _undone);
	}

	// 转发给执行器单元
	_exec_unit->on_order(localid, stdCode, isBuy, leftover, price, isCanceled);
}

/*!
 * \brief 处理成交事件
 * 
 * \param localid 本地订单ID
 * \param stdCode 标准合约代码
 * \param isBuy 是否为买单
 * \param vol 成交数量
 * \param fireprice 触发价格
 * \param price 成交价格
 * \param ordTime 订单时间
 * 
 * \details 处理来自撮合引擎的成交事件。主要功能：
 *          1. 计算时间戳和Unix时间
 *          2. 记录详细的成交信息到交易日志
 *          3. 更新持仓数量和未完成订单计数
 *          4. 将成交信息转发给执行器单元
 *          
 *          成交后的状态更新：
 *          - 持仓数量：买入为正，卖出为负
 *          - 未完成订单：减少相应的成交数量
 *          
 *          交易日志记录格式：
 *          localid,signaltime,ordertime,bs,sigprice,ordprice,lmtprice,tradetime,trdprice,qty,sigtimespan,exectime,cancel
 */
void ExecMocker::handle_trade(uint32_t localid, const char* stdCode, bool isBuy, double vol, double fireprice, double price, uint64_t ordTime)
{
	// 计算时间戳
	uint64_t curTime = (uint64_t)_last_tick->actiondate() * 1000000000 + _last_tick->actiontime();
	uint64_t curUnixTime = TimeUtils::makeTime(_last_tick->actiondate(), _last_tick->actiontime());

	uint64_t sigUnixTime = TimeUtils::makeTime((uint32_t)(_sig_time / 10000), _sig_time % 10000 * 100000);
	uint64_t ordUnixTime = TimeUtils::makeTime((uint32_t)(ordTime / 1000000000), ordTime % 1000000000);

	// 确保有有效的信号价格
	if (_sig_px == DBL_MAX)
		_sig_px = _last_tick->preclose();

	// 记录成交信息到交易日志
	_trade_logs << localid << ","
		<< _sig_time << ","
		<< ordTime << ","
		<< (isBuy?"B":"S") << ","
		<< _sig_px << ","
		<< fireprice << ","
		<< price << ","
		<< curTime << ","
		<< price << ","
		<< vol << ","
		<< curUnixTime - sigUnixTime << ","
		<< curUnixTime - ordUnixTime << ","
		<< "false" << std::endl;

	// 更新持仓和未完成订单
	_position += vol* (isBuy?1:-1);
	_undone -= vol * (isBuy ? 1 : -1);
	WTSLogger::info_f("{}, undone orders updated: {}", __FUNCTION__, _undone);
	WTSLogger::info_f("Position updated: {}", _position);

	// 转发给执行器单元
	_exec_unit->on_trade(localid, stdCode, isBuy, vol, price);
}

/*!
 * \brief 处理回放完成事件
 * 
 * \details 处理历史数据回放完成事件。主要功能：
 *          1. 创建输出目录（exec文件夹）
 *          2. 生成交易日志文件名（trades_执行器ID.csv）
 *          3. 将内存中的交易日志写入文件
 *          
 *          输出文件路径：输出目录/exec/trades_执行器ID.csv
 *          交易日志包含了所有的委托、成交、撤单记录，用于后续的交易分析。
 */
void ExecMocker::handle_replay_done()
{
	// 创建输出目录
	std::string folder = WtHelper::getOutputDir();
	folder += "exec/";
	boost::filesystem::create_directories(folder.c_str());

	// 生成交易日志文件并写入内容
	std::stringstream ss;
	ss << folder << "trades_" << _id << ".csv";
	std::string filename = ss.str();
	StdFile::write_file_content(filename.c_str(), _trade_logs.str());
}